/**
 * @author YinHang
 */
;(function () {
	window.World = function (map) {
		this.map = map;
		this.height = this.map.getHeight();
		this.width = this.map.getWidth();
		this.enemys = new EnemyGroup();
		this.newEnemys = new EnemyGroup();
		this.towers = [];
		this.mapSprite = this.map.getMapSprite();
		this.mapSpriteWidth = this.mapSprite.getWidth();
		this.mapSpriteHeight = this.mapSprite.getHeight();
		this.halfMapSpriteWidth = this.mapSpriteWidth / 2;
		this.halfMapSpriteHeight = this.mapSpriteHeight / 2;
		this.beDead = [];
		this.towerList = [];
		this.towerPrototypeList = [];
		this.playerHp = 20;
		this.playerGold = 0;
	};
	
	//地图贴图类型常量
	World.MAPBLOCK_START = 2;
	World.MAPBLOCK_END = 3;
	World.MAPBLOCK_ROAD = 5;
	World.MAPBLOCK_TOWER = 4;
	World.MAPBLOCK_WALL = 1
	//地图方向常量
	World.DIR_UP = 0;
	World.DIR_RIGHT = 1;
	World.DIR_DOWN = 2;
	World.DIR_LEFT = 3;
	
	//-静态方法定义
	//记录一个路块的估价
	World.MarkCost = function (costList, startBlock, costToStart, costToEnd) {
		World.MarkDataTo2DArray(costList, startBlock.col, startBlock.row, {costToStart: costToStart, costToEnd: costToEnd});
	};
	
	World.MarkParent = function (parentList, block, parent) {
		World.MarkDataTo2DArray(parentList, block.col, block.row, parent);
	};
	
	World.MarkClosed = function (closedList, block) {
		World.MarkDataTo2DArray(closedList, block.col, block.row, true);
	};
	
	World.MarkDataTo2DArray = function (arr, col, row, data) {
		if(!arr)
			arr = [];
		if(!arr[col])
			arr[col] = [];
		arr[col][row] = data;
	};
	
	//按block为条件从数组中取得一个对象
	World.GetObjByBlock = function (array, block) {
		if(!array)
			return null;
		var col = array[block.col];
		if(col)
		{
			var info = col[block.row];
			return info ? info : null;
		}
		return null;
	};
	
	//按估价高低添加贴图
	World.AddOpened = function (openedList, costList, block) {
		if(!openedList)
			openedList = [];
		openedList.push(block);
	};
	
	//从一个正确的路径block，生成一个最终路径数组.
	World.MakePathFromBlock = function (parentList, block) {
		var finalPath = [];
		var parent = World.GetParent(parentList, block);
		while(parent) {
			finalPath.push(block.y);
			finalPath.push(block.x);
			block = parent;
			parent = World.GetParent(parentList, block);
		}
		return finalPath;
	};
	
	//取得两点间的距离
	World.GetLength = function (x1, y1, x2, y2) {
		var dx = x1 + x2;
		var dy = y1 + y2;
        return Math.sqrt(dx * dx, dy * dy);
	};
	
	//图块为索引搜索一个数组
	World.BlockInArray = function (array, block) {
		return World.GetObjByBlock(array, block) ? true : false;
	};
	
	//取得一个估价
	World.GetCost = function (costList, block) {
		var cost = World.GetObjByBlock(costList, block);
		return cost ? cost : null;
	};
	
	//取得一个父图块
	World.GetParent = function (parentList, block) {
		var parent = World.GetObjByBlock(parentList, block);
		return parent ? parent : null;
	};
	
	//isClosed block?
	World.IsClosed = function (closedList, block) {
		return World.GetObjByBlock(closedList, block) ? true : false;
	};
	
	//IsOpened block?
	World.IsOpened = function (openedList, block) {
		if(!openedList || openedList.length <= 0)
			return false;
		var openedListLength = openedList.length;
		for(var i=0;i<openedListLength;++i)
		{
			if(openedList[i] == block)
				return true;
		}
		return false;
	};
	
	//-原型定义
	var Prototype = window.World.prototype;
	
	Prototype.draw = function (g) {
		this.map.draw(g);
		this.drawEnemys(g);
		this.drawTowerTypes(g);
		this.drawTowers(g);
	};
	
	Prototype.working = function () {
		this.beBornEnemy();
		this.enemysThinking();
		this.towerAttach();
		this.doKills();
	};
	
	Prototype.beBornEnemy = function () {
		var beBornList = [];
		for(var i=this.newEnemys.iterator();i.hasNext();)
		{
			var enemy = i.next();
			if(enemy.canBorn())
				beBornList.push(enemy);
		}
		var beBornListLength = beBornList.length;
		for(var i=0;i<beBornListLength;++i)
		{
			this.newEnemys.remove(beBornList[i])
			this.anEnemyGo(beBornList[i]);
		}
	};
	
	Prototype.doKills = function () {
		var killsLength = this.beDead.length;
		for(var i=0;i<killsLength;++i)
			this.beDead[i].dead();
		this.beDead = [];
	};
	
	Prototype.getTowerList = function () {
		return this.towerList;
	};
	
	Prototype.getMap = function () {
		return this.map;
	};
	
	var RectCollision = Gamepackage.ui.g2d.physics.Physics.RectCollision;
	var RectCollision = Gamepackage.ui.g2d.physics.Physics.RectCollision;
	
	Prototype.enemysThinking = function () {
		for(var i=this.enemys.iterator();i.hasNext();)
		{
			var enemy = i.next();
			enemy.go(this.halfMapSpriteWidth, this.halfMapSpriteHeight);
			if(enemy.getHp() <= 0)
				this.beDead.push(enemy);
		}
	};
	
	Prototype.generateEnemyPath = function (enemy) {
		var curBlock = this.map.blockCollisionWithRect(enemy.getX(), enemy.getY(), enemy.getWidth(), enemy.getHeight());
		var endBlock = this.map.getFirstBlock(World.MAPBLOCK_END);
		enemy.setPath(this.pathFinder(this.map.getMapArr(), [World.MAPBLOCK_START, World.MAPBLOCK_ROAD, World.MAPBLOCK_END], curBlock, endBlock));
	};
	
	Prototype.pathFinder = function (map, allows, startBlock, endBlock) {
		var openedList = [];
		var costList = [];
		var closedList = [];
		var parentList = [];
		World.MarkParent(parentList, startBlock, null);
		//加入打开节点列表准备运算
		World.AddOpened(openedList, costList, startBlock);
		
		//当无节点可运算的时候退出循环
		while(openedList.length > 0)
		{
			//随意弹出第一个有效节点
			var firstBlock = openedList.shift();
			//到达终点了!
			if(firstBlock.frame == endBlock.frame)
				return World.MakePathFromBlock(parentList, firstBlock);
			else
			{
				//已经运算过的节点加入closed列表
				World.MarkClosed(closedList, firstBlock);
				//取得四个方向上所有的节点
				var roadList = this.findRoad(firstBlock);
				var roadListLength = roadList.length;
				for(var i=0;i<roadListLength;++i)
				{
					var road = roadList[i];
					//如果不是等待运算的节点，也不是已经运算结束的节点，并且是可以通过的节点时，将其加入opended列表待运算.
					if(!World.IsOpened(openedList, road) && !World.IsClosed(closedList, road) && this.isEnabledRoad(road, allows)) 
					{
						//待运算的节点的父节点都默认定为firstblock，也即是刚才弹出的元素.
						World.MarkParent(parentList, road, firstBlock);
						//add to openedlist
						World.AddOpened(openedList, costList, road);
					}
				}
			}
		}
		return null;
	};
	
	Prototype.towerAttach = function () {
		var towerNum = this.towerList.length;
		for(var i=0;i<towerNum;++i)
			this.towerList[i].sightAllEnemy(this.enemys);
	};
	
	
	//根据排除图块判断是否是允许路段
	Prototype.isEnabledRoad = function (block, enabledRoadArr) {
		var erLength = enabledRoadArr.length;
		for(var i=0;i<erLength;++i)
		{
			if(enabledRoadArr[i] == block.frame)
				return true;
		}
		return false;
	};
	
	Prototype.findRoad = function (block) {
		var roadList = [];
		var leftRoad = this.map.getLeftBlock(block);
		var rightRoad = this.map.getRightBlock(block);
		var upRoad = this.map.getUpBlock(block);
		var downRoad = this.map.getDownBlock(block);
		if(leftRoad)
			roadList.push(leftRoad);
		if(rightRoad)
			roadList.push(rightRoad);
		if(upRoad)
			roadList.push(upRoad);
		if(downRoad)
			roadList.push(downRoad);
		return roadList;
	};
	
	Prototype.destroyAnEnemy = function (entityNode) {
		this.enemys.remove(entityNode);
	};
	
	Prototype.anEnemyGo = function (enemy) {
		var startBlock = this.map.getFirstBlock(World.MAPBLOCK_START);
		if(startBlock)
		{
			enemy.setX(startBlock.x + this.map.getBlockWidth() / 2 - enemy.getWidth() / 2);
			enemy.setY(startBlock.y + this.map.getBlockHeight() / 2 - enemy.getHeight() / 2);
			this.generateEnemyPath(enemy);
			var index = this.enemys.add(enemy);
			enemy.setWorld(this);
			enemy.setId(index);
		}
	};
	
	Prototype.drawEnemys = function (g) {
		for(var i=this.enemys.iterator();i.hasNext();)
		{
			var enemy = i.next();
			enemy.draw(g);
		}
	};
	
	Prototype.drawTowers = function (g) {
		var towerNum = this.towerList.length;
		for(var i=0;i<towerNum;++i)
			this.towerList[i].draw(g);
	};
	
	Prototype.drawTowerTypes = function (g) {
		var towerPrototypeNum = this.towerPrototypeList.length;
		for(var i=0;i<towerPrototypeNum;++i)
			this.towerPrototypeList[i].draw(g);
	};
	
	Prototype.addTowerPrototype = function (tower) {
		var allPosition = this.map.getBlocks(World.MAPBLOCK_TOWER);
		var positionNum = allPosition.length;
		var curTowerTypeNum = this.towerPrototypeList.length;
		var room = null;
		for(var i=0;i<positionNum;++i)
		{
			room = allPosition[i];
			for(var j=0;j<curTowerTypeNum;++j)
			{
				if(this.towerPrototypeList[j].getY() == allPosition[i].y)
				{
					room = null;
					break;
				}
			}
			if(room)
				break;
		}
		if(room != null)
		{
			tower.setX(room.x);
			tower.setY(room.y);
			this.towerPrototypeList.push(tower);
		}
	};
	
	Prototype.fetchTower = function (x, y) {
		var curTowerTypeNum = this.towerPrototypeList.length;
		for(var i=0;i<curTowerTypeNum;++i)
		{
			if(this.towerPrototypeList[i].collisionWithRect(x, y, 1, 1))
				return this.towerPrototypeList[i];
		}
	};
	
	Prototype.addTower = function (tower) {
		tower.doActivation();
		this.towerList.push(tower);
	};
	
	Prototype.addEnemy = function (enemy) {
		this.newEnemys.add(enemy);
	};
})();
